package cn.donting.jme.utile;

import cn.donting.jme.EditorContent;
import cn.donting.jme.editor.scene.Scene;
import com.jme3.asset.*;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioKey;
import com.jme3.export.Savable;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.export.binary.BinaryImporter;
import com.jme3.font.BitmapFont;
import com.jme3.material.Material;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.Caps;
import com.jme3.scene.Spatial;
import com.jme3.shader.ShaderGenerator;
import com.jme3.texture.Texture;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.List;

/**
 * Savable 工具
 * 保存，加载
 */
@Slf4j
public class SaveUtil {


    public static Scene loadScene(File file) throws IOException {
        BinaryImporter binaryImporter = new BinaryImporter();
        AssetManagerProxy assetManagerProxy = new AssetManagerProxy(EditorContent.getJmeApplication().getAssetManager());
        binaryImporter.setAssetManager(assetManagerProxy);
        return (Scene) binaryImporter.load(file);
    }

    public static <T> T load(InputStream inputStream) throws IOException {
        BinaryImporter binaryImporter = new BinaryImporter();
        binaryImporter.setAssetManager(EditorContent.getJmeApplication().getAssetManager());
        return (T) binaryImporter.load(inputStream);
    }

    public static void save(File file, Savable scene) throws IOException {
        log.info("save Savable:{}", file);
        BinaryExporter binaryExporter = new BinaryExporter();
        binaryExporter.save(scene, file);
    }

    public static Spatial loadModel(File file) throws IOException {
        BinaryImporter binaryImporter = new BinaryImporter();
        AssetManagerProxy assetManagerProxy = new AssetManagerProxy(EditorContent.getJmeApplication().getAssetManager());
        binaryImporter.setAssetManager(assetManagerProxy);
        return (Spatial) binaryImporter.load(file);
    }

    /**
     * 用于加载 缓存Material，使加载的 j3m 是同一对象
     */
    private static class AssetManagerProxy implements AssetManager {

        private AssetManager assetManager;

        public AssetManagerProxy(AssetManager assetManager) {
            this.assetManager = assetManager;
        }

        @Override
        public void addClassLoader(ClassLoader loader) {
            assetManager.addClassLoader(loader);
        }

        @Override
        public void removeClassLoader(ClassLoader loader) {
            assetManager.removeClassLoader(loader);
        }

        @Override
        public List<ClassLoader> getClassLoaders() {
            return assetManager.getClassLoaders();
        }

        @Override
        public void registerLoader(Class<? extends AssetLoader> loaderClass, String... extensions) {
            assetManager.registerLoader(loaderClass, extensions);
        }

        @Override
        public void unregisterLoader(Class<? extends AssetLoader> loaderClass) {
            assetManager.unregisterLoader(loaderClass);
        }

        @Override
        public void registerLocator(String rootPath, Class<? extends AssetLocator> locatorClass) {

        }

        @Override
        public void unregisterLocator(String rootPath, Class<? extends AssetLocator> locatorClass) {

        }

        @Override
        public void addAssetEventListener(AssetEventListener listener) {

        }

        @Override
        public void removeAssetEventListener(AssetEventListener listener) {

        }

        @Override
        public void clearAssetEventListeners() {

        }

        @Override
        public AssetInfo locateAsset(AssetKey<?> key) {
            return assetManager.locateAsset(key);
        }

        @Override
        public <T> T loadAssetFromStream(AssetKey<T> key, InputStream inputStream) {
            return assetManager.loadAssetFromStream(key, inputStream);
        }

        @Override
        public <T> T loadAsset(AssetKey<T> key) {
            return assetManager.loadAsset(key);
        }

        @Override
        public Object loadAsset(String name) {
            return assetManager.loadAsset(name);
        }

        @Override
        public Texture loadTexture(TextureKey key) {
            return assetManager.loadTexture(key);
        }

        @Override
        public Texture loadTexture(String name) {
            return assetManager.loadTexture(name);
        }

        @Override
        public AudioData loadAudio(AudioKey key) {
            return assetManager.loadAudio(key);
        }

        @Override
        public AudioData loadAudio(String name) {
            return assetManager.loadAudio(name);
        }

        @Override
        public Spatial loadModel(ModelKey key) {
            return assetManager.loadModel(key);
        }

        @Override
        public Spatial loadModel(String name) {
            return assetManager.loadModel(name);
        }

        @Override
        public Material loadMaterial(String name) {
            MaterialKey materialKey = new MaterialKey(name);
            Material fromCache = assetManager.getFromCache(materialKey);
            if (fromCache == null) {
                assetManager.loadAsset(materialKey);
                fromCache = assetManager.getFromCache(materialKey);
                fromCache.setKey(materialKey);
            }
            return fromCache;
        }

        @Override
        public BitmapFont loadFont(String name) {
            return assetManager.loadFont(name);
        }

        @Override
        public FilterPostProcessor loadFilter(FilterKey key) {
            return assetManager.loadFilter(key);
        }

        @Override
        public FilterPostProcessor loadFilter(String name) {
            return assetManager.loadFilter(name);
        }

        @Override
        public void setShaderGenerator(ShaderGenerator generator) {
            assetManager.setShaderGenerator(generator);
        }

        @Override
        public ShaderGenerator getShaderGenerator(EnumSet<Caps> caps) {
            return assetManager.getShaderGenerator(caps);
        }

        @Override
        public <T> T getFromCache(AssetKey<T> key) {
            return assetManager.getFromCache(key);
        }

        @Override
        public <T> void addToCache(AssetKey<T> key, T asset) {
            assetManager.addToCache(key, asset);
        }

        @Override
        public <T> boolean deleteFromCache(AssetKey<T> key) {
            return assetManager.deleteFromCache(key);
        }

        @Override
        public void clearCache() {
            assetManager.clearCache();
        }
    }
}
